﻿#region Includes

using System;
using System.ComponentModel;
using System.Reflection;
using System.Text;
using System.Linq;
using System.Windows.Forms;
using System.Configuration;
using System.Collections.Generic;
using NLog.Config;
using NLog.Targets;
using NLog;
using ArtheaEngine.Model;

#endregion

namespace ArtheaServer
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();

            var worlds = new List<World>();

            var context = new ArtheaModelContainer();

            if (context.Worlds.Count() == 0)
            {
                context.Worlds.AddObject(new World { Name = "Arthea", Port = 3778 });

                context.SaveChanges();
            }
            if (context.Races.Count() == 0)
            {
                context.Races.AddObject(new HumanRace());
                context.Races.AddObject(new DwarfRace());
                context.SaveChanges();
            }

            if (context.Classes.Count() == 0)
            {
                context.Classes.AddObject(new MageClass());
                context.Classes.AddObject(new WarriorClass());
                context.SaveChanges();
            }
            foreach (var entry in context.Worlds)
            {
                var mi = new ToolStripMenuItem(entry.Name);

                var miStart = new ToolStripMenuItem("Start") { Tag = entry.Clone() };
                miStart.Click += miStart_Click;
                mi.DropDownItems.Add(miStart);

                worldToolStripMenuItem.DropDownItems.Add(mi);
            }


        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var buf = new StringBuilder();

            var assName = Assembly.GetAssembly(typeof (World)).GetName(false);

            var vrs = assName.Version;

            buf.Append(assName.Name).Append(": v");
            buf.AppendFormat("{0}.{1}.{2}", vrs.Major, vrs.Minor, vrs.Build);
            buf.AppendLine();
            buf.AppendLine();

            assName = Assembly.GetAssembly(typeof (Server)).GetName(false);

            vrs = assName.Version;

            buf.Append(assName.Name).Append(": v");
            buf.AppendFormat("{0}.{1}.{2}", vrs.Major, vrs.Minor, vrs.Build);
            buf.AppendLine();
            buf.AppendLine();

            buf.AppendLine("Copyright " + DateTime.Now.ToString("yyyy") + " Ryan Jennings.");

            MessageBox.Show(buf.ToString(), "About", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            foreach (ToolStripMenuItem world in worldToolStripMenuItem.DropDownItems)
            {
                foreach (ToolStripMenuItem mi in world.DropDownItems)
                {
                    if (mi.Tag is Server)
                    {
                        var server = mi.Tag as Server;

                        server.Stop();
                    }
                }
            }
        }

        private void MainForm_Resize(object sender, EventArgs e)
        {
            if (FormWindowState.Minimized == WindowState && minimizeToTrayToolStripMenuItem.Checked)
            {
                Hide();
                notifier.Visible = true;
            }
        }

        private void miStart_Click(object sender, EventArgs e)
        {
            var mi = sender as ToolStripMenuItem;

            if (mi == null) return;

            if (mi.Tag is World)
            {
                var world = mi.Tag as World;
                mi.Tag = StartWorld(world);
                mi.Text = "&Stop";
            }
            else if (mi.Tag is Server)
            {
                var server = mi.Tag as Server;
                mi.Tag = StopWorld(server);
                mi.Text = "&Start";
            }
        }

        private void notifier_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            RestoreMainForm();
        }

        private void notifierContextMenu_Closing(object sender, ToolStripDropDownClosingEventArgs e)
        {
            mainMenu.Items.Add(worldToolStripMenuItem);
        }

        private void notifierContextMenu_Opening(object sender, CancelEventArgs e)
        {
            notifierContextMenu.Items.Add(worldToolStripMenuItem);
        }

        private void Output_Enter(object sender, EventArgs e)
        {
            mainMenu.Focus();
        }

        private void RestoreMainForm()
        {
            Show();
            notifier.Visible = false;
            WindowState = FormWindowState.Normal;
        }

        private void restoreToolStripMenuItem_Click(object sender, EventArgs e)
        {
            RestoreMainForm();
        }

        private Server StartWorld(World world)
        {
            var server = new Server(world);
            var tabPage = new TabPage(world.Name);

            var output = new RichTextBox();
            output.Enter += Output_Enter;
            output.Name = world.Name;
            output.Dock = DockStyle.Fill;
            tabPage.Controls.Add(output);

            RichTextBoxTarget target = new RichTextBoxTarget();
            target.Layout = "${date:format=HH\\:MM\\:ss} ${logger} ${message}";
            target.ControlName = world.Name;
            target.FormName = this.Name;
            target.UseDefaultRowColoringRules = false;

            SimpleConfigurator.ConfigureForTargetLogging(target, LogLevel.Trace);

            tabControl1.TabPages.Add(tabPage);

            server.Start();

            return server;
        }

        private World StopWorld(Server server)
        {
            server.Stop();
            foreach (TabPage tabPage in tabControl1.TabPages)
            {
                if (tabPage.Name == server.World.Name)
                {
                    tabControl1.TabPages.Remove(tabPage);
                    break;
                }
            }
            return server.World;
        }
    }

    public class WorldConfiguration : ConfigurationSection
    {
        [ConfigurationProperty("worlds")]
        public WorldCollection WorldItems
        {
            get { return ( (WorldCollection)( base[ "worlds" ] ) ); }
        }
    }

    [ConfigurationCollection(typeof(WorldCollection), AddItemName = "world")]
    public class WorldCollection : ConfigurationElementCollection
    {
        protected override ConfigurationElement CreateNewElement()
        {
            return new WorldElement();
        }
 
        protected override object GetElementKey( ConfigurationElement element )
        {
            return ( (WorldElement)( element ) ).Name;
        }
 
        public WorldElement this[int idx ]
        {
            get
            {
                return (WorldElement) BaseGet(idx);
            }
        }
    }

    public class WorldElement : ConfigurationElement
    {
 
        [ConfigurationProperty("name", DefaultValue="", IsKey=true, IsRequired=true)]
        public string Name
        {
            get
            {
                return ((string) (base["name"]));
            }
            set
            {
                base["name"] = value;
            }
        }
 
        [ConfigurationProperty( "connectionString", DefaultValue = "", IsKey = false, IsRequired = true )]
        public string ConnectionString
        {
            get
            {
                return ( (string)( base[ "connectionString" ] ) );
            }
            set
            {
                base[ "connectionString" ] = value;
            }
        }

        [ConfigurationProperty( "port", DefaultValue = "4000", IsKey = false, IsRequired = false)]
        public short Port
        {
            get
            {
                return ( (short) ( base[ "port" ] ) );
            }
            set
            {
                base[ "port" ] = value;
            }
        }
 
    }
}